package com.project.biz.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.project.biz.CmsProductSkuBiz;
import com.project.common.enums.LockEnum;
import com.project.common.exception.ServiceException;
import com.project.entity.CmsProductSku;
import com.project.mapper.CmsProductSkuMapper;
import com.project.pojo.model.UpdateProductSkuModel;
import com.project.redis.RedisClient2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @Description: 商品SKU业务层接口实现类
 * @Author: zhuchi
 * @CreateDate: 2020/10/15 15:14
 * @Version: 1.0
 */
@Slf4j
@Service
public class CmsProductSkuBizImpl extends ServiceImpl<CmsProductSkuMapper, CmsProductSku> implements CmsProductSkuBiz {

    /**
     * Redis服务
     */
    @Autowired
    private RedisClient2 redisClient2;

    /**
     * 添加/修改商品SKU信息
     * @param productSkus
     * @param productId
     * @return
     */
    public int updateProductSku(List<UpdateProductSkuModel> productSkus, Long productId){
        //清空商品现有SKU信息
        QueryWrapper<CmsProductSku> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_id", productId);
        this.baseMapper.delete(queryWrapper);

        if (null != productSkus && productSkus.size() > 0){
            int insertProductSku = this.baseMapper.insertProductSku(productSkus, productId);
            return insertProductSku;
        }

        return 0;
    }

    /**
     * 获取商品SKU信息
     * @param productId
     * @return
     */
    public List<CmsProductSku> getProductSku(Long productId){
        QueryWrapper<CmsProductSku> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_id", productId);
        return this.baseMapper.selectList(queryWrapper);
    }

    /**
     * 商品SKU减库存
     * @param skuId
     * @param num
     * @param productName 商品名称
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 30)
    public int updateProductSkuStock(Long skuId, Integer num, String productName){
        int result = 0;
        //商品SKU减库存分布式锁
        String updateProductSkuStock_lock = LockEnum.UPDATE_PRODUCT_SKU_STOCK.Value() + skuId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //商品SKU加锁
        if (this.redisClient2.lock(updateProductSkuStock_lock, String.valueOf(expires))){
            try {
                CmsProductSku productSku = this.baseMapper.selectById(skuId);
                if (productSku.getStock() >= num){
                    productSku.setStock(productSku.getStock() - num);
                    result = this.baseMapper.updateById(productSku);
                }else {
                    throw new ServiceException("商品["+productName+"]库存不足");
                }
            }catch (Exception e){
                e.printStackTrace();
                log.info("商品SKU[{}]减库存时发生异常,减少数量:{}", skuId, num);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateProductSkuStock_lock, String.valueOf(expires));
            }
        }else {
            //购买人数较多，请稍后再试
            throw new ServiceException("购买人数较多,请稍后再试");
        }

        return result;
    }

    /**
     * 商品SKU加库存
     * @param skuId
     * @param num
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 30)
    public int updateAddProductSkuStock(Long skuId, Integer num){
        int result = 0;
        //商品SKU加库存分布式锁
        String updateAddProductSkuStock_lock = LockEnum.UPDATE_ADD_PRODUCT_SKU_STOCK.Value() + skuId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //商品SKU加锁
        if (this.redisClient2.lock(updateAddProductSkuStock_lock, String.valueOf(expires))){
            try {
                CmsProductSku productSku = this.baseMapper.selectById(skuId);
                if (null != productSku){
                    productSku.setStock(productSku.getStock() + num);
                    result = this.baseMapper.updateById(productSku);
                }
            }catch (Exception e){
                e.printStackTrace();
                log.info("商品SKU[{}]加库存时发生异常,增加数量:{}", skuId, num);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(updateAddProductSkuStock_lock, String.valueOf(expires));
            }
        }else {
            //购买人数较多，请稍后再试
            throw new ServiceException("购买人数较多,请稍后再试");
        }

        return result;
    }

    /**
     * 增加SKU单品销量
     * @param skuId
     * @param num
     * @return
     */
    @Transactional(rollbackFor = Exception.class , isolation = Isolation.REPEATABLE_READ, timeout = 30)
    public int addSkuSales(Long skuId, Integer num){
        int result = 0;
        //增加SKU单品销量分布式锁
        String addSkuSales_lock = LockEnum.ADD_SKU_SALES.Value() + skuId;
        //超时时间（15秒）
        Long expires = System.currentTimeMillis() + Long.parseLong(LockEnum.LOCK_EXPIRES.Value());
        //商品SKU加锁
        if (this.redisClient2.lock(addSkuSales_lock, String.valueOf(expires))){
            try {
                CmsProductSku productSku = this.baseMapper.selectById(skuId);
                if (null != productSku){
                    productSku.setSales(productSku.getSales() + num);
                    result = this.baseMapper.updateById(productSku);
                }
            }catch (Exception e){
                e.printStackTrace();
                log.info("增加SKU[{}]单品销量时发生异常,增加数量:{}", skuId, num);
                throw new ServiceException(e.getMessage());
            }finally {
                //解锁
                this.redisClient2.unlock(addSkuSales_lock, String.valueOf(expires));
            }
        }else {
            //操作太频繁了，请稍后再试
            throw new ServiceException("操作太频繁了,请稍后再试");
        }

        return result;
    }

}
